package encrypt;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import lombok.AllArgsConstructor;
import lombok.Data;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA
 * SHA1withRSA
 * 基本使用
 */
public class RSAUtils {

    public static String RSA = "RSA";
    public static String SHA1_WITH_RSA = "SHA1withRSA";

    /**
     * 密钥长度，DSA算法的默认密钥长度是1024
     * 密钥长度必须是64的倍数，在512到65536位之间
     */
    private static final int KEY_SIZE = 1024;

    public static void main(String[] args) throws Exception {
        test1();
//        test2();
//        test3();
    }


    /**
     * 公钥加密 私钥解密
     */
    public static void test1() throws Exception {
        String password = "1234abcd5678";
        KeyStore keys = createKeys();
        byte[] publicKey = getPublicKey(keys);
        byte[] privateKey = getPrivateKey(keys);
        System.out.println("公钥：" + Base64.encode(publicKey));
        System.out.println("私钥：" + Base64.encode(privateKey));

        byte[] encryptPublicByte = encryptByPublicKey(password.getBytes(), publicKey);
        System.out.println("使用公钥加密后的数据：" + Base64.encode(encryptPublicByte));

        byte[] decryptByPrivateKey = decryptByPrivateKey(encryptPublicByte, privateKey);
        System.out.println("使用私钥解密后的数据：" + new String(decryptByPrivateKey));
    }

    /**
     * 私钥加密 公钥解密
     */
    public static void test2() throws Exception {
        String password = "1234abcd5678";
        KeyStore keys = createKeys();
        byte[] publicKey = getPublicKey(keys);
        byte[] privateKey = getPrivateKey(keys);
        System.out.println("公钥：" + Base64.encode(publicKey));
        System.out.println("私钥：" + Base64.encode(privateKey));

        byte[] encryptByPrivateKey = encryptByPrivateKey(password.getBytes(), privateKey);
        System.out.println("使用私钥加密后的数据：" + Base64.encode(encryptByPrivateKey));

        byte[] decryptByPublicKey = decryptByPublicKey(encryptByPrivateKey, publicKey);
        System.out.println("使用公钥解密后的数据：" + new String(decryptByPublicKey));
    }

    /**
     * 使用 SHA1withRSA 签名
     * 使用 SHA1withRSA 验证签名
     */
    private static void test3() throws Exception {
        KeyPairGenerator gen = KeyPairGenerator.getInstance(RSA);
        gen.initialize(2048);
        KeyPair pair = gen.generateKeyPair();
        //rsa生成一对公私钥
        PublicKey publicKey = pair.getPublic();
        PrivateKey privateKey = pair.getPrivate();
        System.out.println("公钥" + Base64.encode(publicKey.getEncoded()));
        System.out.println("私钥" + Base64.encode(privateKey.getEncoded()));

        //SHA1withRSA算法进行---私钥签名
        Signature sign = Signature.getInstance(SHA1_WITH_RSA);
        sign.initSign(privateKey);
        byte[] data = "sss".getBytes();
        sign.update(data);//更新用于签名的数据
        byte[] signature = sign.sign();//生成签名
        String signatureStr = Base64.encode(signature);
        System.out.println("签名:"+signatureStr);

        //SHA1withRSA算法进行---公钥验签
        Signature verifySign = Signature.getInstance(SHA1_WITH_RSA);
        verifySign.initVerify(publicKey);
        verifySign.update(data);//用于验签的数据
        boolean flag = verifySign.verify(Base64.decode(signatureStr));//上一步的签名结果
        System.out.println("签名结果" + flag);
    }

    /**
     * 生成密钥对
     *
     * @return 密钥对对象
     * @throws NoSuchAlgorithmException
     */
    public static KeyStore createKeys() throws NoSuchAlgorithmException {
        //KeyPairGenerator用于生成公钥和私钥对。密钥对生成器是使用 getInstance 工厂方法
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA);
        keyPairGenerator.initialize(KEY_SIZE);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        KeyStore keyStore = new KeyStore(publicKey, privateKey);
        return keyStore;
    }

    /**
     * 获取私钥
     *
     * @param keyStore
     * @return
     */
    private static byte[] getPrivateKey(KeyStore keyStore) {
        return ((RSAPrivateKey) keyStore.privateKey).getEncoded();
    }

    /**
     * 获取公钥
     *
     * @param keyStore
     * @return
     */
    private static byte[] getPublicKey(KeyStore keyStore) {
        return ((RSAPublicKey) keyStore.publicKey).getEncoded();
    }

    /**
     * 私钥加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return byte[] 加密数据
     */
    public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {

        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥加密
     *
     * @param data
     * @param key
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws InvalidKeyException
     */
    private static byte[] encryptByPublicKey(byte[] data, byte[] key) throws NoSuchAlgorithmException,
            InvalidKeySpecException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
        //实例化密钥工厂
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        //初始化公钥,根据给定的编码密钥创建一个新的 X509EncodedKeySpec。
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }


    /**
     * 私钥解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {

        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        //产生公钥
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }


    //定义密钥类
    @Data
    @AllArgsConstructor
    public static class KeyStore {
        private Object publicKey;
        private Object privateKey;
    }


}
